home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Visual Cafe Pro v1.0 / SOURCE.BIN / BaseTabbedPanel.java < prev    next >
Encoding:
Java Source  |  1997-06-19  |  26.7 KB  |  1,054 lines

  1. /*
  2.  Copyright (c) 1995, 1996 Connect! Corporation, Inc. All Rights Reserved.
  3.  Source code usage restricted as defined in Connect! Widgets License Agreement
  4. */
  5.  
  6. package symantec.itools.awt;
  7.  
  8. import java.awt.*;
  9. import java.applet.Applet;
  10. import java.util.Vector;
  11. import java.lang.Boolean;
  12. import java.lang.Integer;
  13.  
  14. /**
  15.  * BaseTabbedPanel is a Panel extension which provides for
  16.  * a tabbed dialog effect. It provides a the visuall aspect of
  17.  * tabs and allows the programmer to decide what action to take
  18.  * when a tab is activated. Can be used directly or extended.
  19.  * When extending from BaseTabbedPanel be sure to super()
  20.  * during construction and to super.handleEvent(evt) from
  21.  * handleEvent if you override it.
  22.  *
  23.  * @author Scott Fauerbach
  24.  */
  25. public abstract class BaseTabbedPanel extends Panel
  26. {
  27.     /**
  28.      * Position constant indicating tabs are to be put on top.
  29.      */
  30.     public static final int TOP = 0;
  31.  
  32.     /**
  33.      * Position constant indicating tabs are to be put at bottom.
  34.      */
  35.     public static final int BOTTOM = 1;
  36.  
  37.     /**
  38.      * Style constant indicating tabs are to have rounded corners.
  39.      */
  40.     public static final int ROUNDED = 0;
  41.  
  42.     /**
  43.      * Style constant indicating tabs are to have square corners.
  44.      */
  45.     public static final int SQUARE = 1;
  46.  
  47.     private int TF_LEFT = 9;
  48.     private int TF_RIGHT = -9;
  49.     private int TF_TOP = 30;
  50.     private int TF_BOTTOM = -9;
  51.  
  52.     private int TF_BTN_HEIGHT = 20;
  53.  
  54.     private Vector vLabels;
  55.     private Vector vEnabled;
  56.     private Vector vPolys;
  57.  
  58.     /**
  59.      * Zero-relative index of currently shown tab. -1 if no tabs exist or are shown.
  60.      */
  61.     protected int curIndex = -1;
  62.  
  63.     private Font fReg;
  64.     private Font fSel;
  65.  
  66.     private Component userPanel = null;
  67.  
  68.     private int iTabsPosition = TOP;
  69.     private int iTabsStyle = ROUNDED;
  70.  
  71.     private int osAdjustment;
  72.  
  73.     private int firstVisibleTab = 0;
  74.     private DirectionButton dbLeft;
  75.     private DirectionButton dbRight;
  76.     private Polygon nullPoly;
  77.     private int lastWidth = -1;
  78.  
  79.     private Insets btpInsets;
  80.  
  81.     /**
  82.      * Constructs a BaseTabbedPanel with tabs on top and rounded.
  83.      */
  84.     public BaseTabbedPanel()
  85.     {
  86.         this(TOP, ROUNDED);
  87.     }
  88.  
  89.     /**
  90.      * Obsolete. Use public BaseTabbedPanel(int tabsPostion, int tabsStyle).
  91.      */
  92.     public BaseTabbedPanel(boolean bTabsOnTop)
  93.     {
  94.         this(bTabsOnTop ? TOP : BOTTOM, bTabsOnTop ? ROUNDED : SQUARE);
  95.     }
  96.  
  97.     /**
  98.      * Constructs a BaseTabbedPanel with the desired tab position 
  99.      * and corner style.
  100.      * @param tabsPostion constant indicating TOP or BOTTOM tab location
  101.      * @param tabsStyle constant indicating ROUNDED or SQUARE tabs
  102.      */
  103.     public BaseTabbedPanel(int tabsPostion, int tabsStyle)
  104.     {
  105.         vLabels = new Vector();
  106.         vEnabled = new Vector();
  107.         vPolys = new Vector();
  108.         btpInsets = new Insets(0,0,0,0);
  109.  
  110.         setTabsInfo(tabsPostion, tabsStyle);
  111.  
  112.         fReg = new Font("Helvetica", Font.PLAIN, 12);
  113.         fSel = new Font("Helvetica", Font.BOLD, 12);
  114.  
  115.         if (System.getProperty("os.name").startsWith("S")) // SunOS, Solaris
  116.             osAdjustment = -1;
  117.         else
  118.             osAdjustment = 0;
  119.  
  120.         super.setLayout(null);
  121.  
  122.         // prepare left/right arrows
  123.         dbLeft = new DirectionButton(DirectionButton.LEFT);
  124.         dbRight = new DirectionButton(DirectionButton.RIGHT);
  125.         dbLeft.setShowFocus(false);
  126.         dbRight.setShowFocus(false);
  127.         dbLeft.shrinkTriangle(1, 1, 0, 1);
  128.         dbRight.shrinkTriangle(1, 1, 0, 1);
  129.         super.add(dbLeft, -1);
  130.         super.add(dbRight, -1);
  131.  
  132.         nullPoly = new Polygon();
  133.         nullPoly.addPoint(0, 0);
  134.         nullPoly.addPoint(1, 1);
  135.         nullPoly.addPoint(0, 0);
  136.     }
  137.  
  138.     /**
  139.      * Sets the position of the tabs to the top or bottom.
  140.      * @param tabsPosition constant indicating TOP or BOTTOM
  141.      */
  142.     public void setTabsPosition(int tabsPosition)
  143.     {
  144.         if (iTabsPosition != tabsPosition)
  145.             setTabsInfo(tabsPosition, iTabsStyle);
  146.     }
  147.  
  148.     /**
  149.      * Gets the current tabs position, TOP or BOTTOM.
  150.      * @return position constant TOP or BOTTOM, indicating the current tabs position
  151.      */
  152.     public int getTabsPosition() {
  153.          return iTabsPosition;
  154.     }
  155.  
  156.     /**
  157.      * Sets the style of the tabs to ROUNDED or SQUARE.
  158.      * @param tabsStyle constant indicating ROUNDED or SQUARE
  159.      */
  160.     public void setTabsStyle(int tabsStyle)
  161.     {
  162.         if (iTabsStyle != tabsStyle)
  163.             setTabsInfo(iTabsPosition, tabsStyle);
  164.     }
  165.  
  166.     /**
  167.      * Gets the current tab style, ROUNDED or SQUARE.
  168.      * @return style constant ROUNDED or SQUARE, indicating the current tab style
  169.      */
  170.     public int getTabsStyle() {
  171.         return iTabsStyle;
  172.     }
  173.  
  174.     /**
  175.      * Sets the position and style of the tabs.
  176.      * @param tabsPosition constant indicating TOP or BOTTOM
  177.      * @param tabsStyle constant indicating ROUNDED or SQUARE
  178.      */
  179.     public void setTabsInfo(int tabsPosition, int tabsStyle)
  180.     {
  181.         iTabsPosition = tabsPosition;
  182.         if (iTabsPosition == TOP)
  183.             iTabsStyle = ROUNDED;
  184.         else
  185.             iTabsStyle = tabsStyle;
  186.  
  187.         if (iTabsStyle == ROUNDED)
  188.             TF_BTN_HEIGHT = 20;
  189.         else
  190.             TF_BTN_HEIGHT = 17;
  191.  
  192.         repaint();
  193.     }
  194.  
  195.     /**
  196.      * Adds the panel to the base panel and shows it.
  197.      * Removes all other (previous) panels from base panel.
  198.      * @param p the Panel to add and show
  199.      */
  200.     public void setPanel(Component p)
  201.     {
  202.         removeAll();
  203.         userPanel = p;
  204.         if (userPanel != null)
  205.         {
  206.             super.add(userPanel, -1);
  207.             userPanel.requestFocus();
  208.         }
  209.     }
  210.  
  211.     /**
  212.      * Adds the panel to the base panel and shows it.
  213.      * Hides all other (previous) panels instead of removing them.
  214.      * @param p the Panel to add and show
  215.      */
  216.     public void showPanel(Component p)
  217.     {
  218.         if (userPanel != null)
  219.             userPanel.hide();
  220.  
  221.         userPanel = p;
  222.         if (userPanel != null)
  223.         {
  224.             Component[] comps = getComponents();
  225.             int l = comps.length;
  226.             int x;
  227.             for (x = 0; x < l; x++)
  228.             {
  229.                 if (comps[x] == userPanel)
  230.                     break;
  231.             }
  232.             if (x == l)
  233.                 super.add(userPanel, -1);
  234.  
  235.             userPanel.show();
  236.             userPanel.requestFocus();
  237.             validate();
  238.             repaint();
  239.         }
  240.     }
  241.  
  242.     /**
  243.      * Adds the next tab label and sets whether it is enabled.
  244.      * @param sLabel the tab label
  245.      * @param bEnabled enable the tab or not
  246.      * @return the zero-relative index of the newly added tab
  247.      */
  248.     public int addTab(String sLabel, boolean bEnabled)
  249.     {
  250.         vLabels.addElement(sLabel);
  251.         vEnabled.addElement(new Boolean(bEnabled));
  252.  
  253.         int index = vLabels.size() - 1;
  254.         if (curIndex == -1 && bEnabled)
  255.             showTab(index);
  256.  
  257.         return (index);
  258.     }
  259.  
  260.     /**
  261.      * Re-sets the tab at the index specified. Allows ability to change tab label.
  262.      * @param sLabel the tab label
  263.      * @param bEnabled enable the tab or not
  264.      * @param index zero-relative index of the tab
  265.      */
  266.     public synchronized void setTab(String sLabel, boolean bEnabled, int index)
  267.     {
  268.         if ((index < 0) || (index >= vLabels.size()))
  269.             return;
  270.  
  271.         if (index == curIndex && !bEnabled)
  272.             return;
  273.  
  274.         try
  275.         {
  276.             vLabels.setElementAt(sLabel, index);
  277.             vEnabled.setElementAt(new Boolean(bEnabled), index);
  278.             repaint();
  279.         }
  280.         catch (ArrayIndexOutOfBoundsException e) {}
  281.     }
  282.  
  283.     /**
  284.      * Re-sets the tab label at the index specified.
  285.      * @param sLabel the tab label
  286.      * @param index zero-relative index of the tab
  287.      */
  288.     public synchronized void setLabel(String sLabel, int index)
  289.     {
  290.         if ((index < 0) || (index >= vLabels.size()))
  291.             return;
  292.  
  293.         try
  294.         {
  295.             vLabels.setElementAt(sLabel, index);
  296.             repaint();
  297.         }
  298.         catch (ArrayIndexOutOfBoundsException e) {}
  299.     }
  300.  
  301.     /**
  302.      * Gets the label for the tab at the index specified.
  303.      * @param index zero-relative index of the tab
  304.      * @return the tab label
  305.      */
  306.     public synchronized String getLabel(int index) {
  307.         if ((index < 0) || (index >= vLabels.size()))
  308.             return "";
  309.  
  310.         try
  311.         {
  312.             return (String)vLabels.elementAt(index);
  313.         }
  314.         catch (ArrayIndexOutOfBoundsException e) {}
  315.         return "";
  316.     }
  317.  
  318.     /**
  319.      * Enables/disables the tab at the index specified.
  320.      * @param bEnabled enable the tab or not
  321.      * @param index zero-relative index of the tab
  322.      */
  323.     public synchronized void setEnabled(boolean bEnabled, int index)
  324.     {
  325.         if ((index < 0) || (index >= vLabels.size()))
  326.             return;
  327.  
  328.         if (index == curIndex && !bEnabled)
  329.             return;
  330.  
  331.         try
  332.         {
  333.             vEnabled.setElementAt(new Boolean(bEnabled), index);
  334.             repaint();
  335.         }
  336.         catch (ArrayIndexOutOfBoundsException e) {}
  337.     }
  338.  
  339.     /**
  340.      * Shows and activates tab at index. Tab position must be enabled.
  341.      * @param index zero-relative index of the tab to show and activate
  342.      */
  343.     public void showTab(int index)
  344.     {
  345.         if ((index < 0) || (index >= vLabels.size()) || index == curIndex)
  346.             return;
  347.  
  348.         if ( tabIsEnabled(index) )
  349.         {
  350.             curIndex = index;
  351.             invalidate();
  352.             validate();
  353.             repaint();
  354.             postEvent(new Event(this, Event.ACTION_EVENT, null));
  355.         }
  356.     }
  357.  
  358.     /**
  359.      * Determine whether or not the tab at the index is enabled.
  360.      * @param index zero-relative index of the tab
  361.      * @return true if the tab at the index is enabled
  362.      */
  363.     public boolean tabIsEnabled(int index)
  364.     {
  365.         if ((index < 0) || (index >= vLabels.size()))
  366.             return false;
  367.  
  368.         try
  369.         {
  370.             Boolean bool = (Boolean) vEnabled.elementAt(index);
  371.             if (bool.booleanValue())
  372.                 return true;
  373.         }
  374.         catch (ArrayIndexOutOfBoundsException e) {}
  375.  
  376.         return false;
  377.     }
  378.  
  379.     /**
  380.      * Determine the current shown/active tab.
  381.      * @return zero-relative index of the current shown/active tab
  382.      */
  383.     public int currentTabIndex()
  384.     {
  385.         return curIndex;
  386.     }
  387.  
  388.     /**
  389.      * Enables or disables tab position based on index.
  390.      * The currently active tab cannot be disabled.
  391.      * @param bEnable true to enable, false to disable
  392.      * @param index zero-relative index of the tab
  393.      */
  394.     public void enableTab(boolean bEnable, int index)
  395.     {
  396.         if ((index < 0) || (index >= vEnabled.size()) || index == curIndex)
  397.             return;
  398.  
  399.         try
  400.         {
  401.             vEnabled.setElementAt(new Boolean(bEnable), index);
  402.             repaint();
  403.         }
  404.         catch (ArrayIndexOutOfBoundsException e) {}
  405.     }
  406.  
  407.     /**
  408.      * Removes a tab based on index.
  409.      * The current active tab cannot be removed.
  410.      * @param index zero-relative index of the tab to remove
  411.      */
  412.     public void removeTab(int index)
  413.     {
  414.         if ((index < 0) || (index >= vEnabled.size()) || index == curIndex)
  415.             return;
  416.  
  417.         try
  418.         {
  419.             vLabels.removeElementAt(index);
  420.             vEnabled.removeElementAt(index);
  421.             repaint();
  422.         }
  423.         catch (ArrayIndexOutOfBoundsException e) {}
  424.     }
  425.  
  426.     /**
  427.      * Removes all tabs.
  428.      */
  429.     public void removeAllTabs()
  430.     {
  431.         vLabels = new Vector();
  432.         vEnabled = new Vector();
  433.         vPolys = new Vector();
  434.         curIndex = -1;
  435.         firstVisibleTab = 0;
  436.         lastWidth = -1;
  437.         removeAll();
  438.         repaint();
  439.     }
  440.  
  441.     /**
  442.      * Handles the laying out of components within this component.
  443.      * This is a standard Java AWT method which gets called by the AWT
  444.      * when this component is validated with the validate() method.
  445.      * 
  446.      * @see java.awt.Container#validate
  447.      */
  448.     public void layout()
  449.     {
  450.         Rectangle r = bounds();
  451.  
  452.         int width = r.width - TF_LEFT + TF_RIGHT;
  453.         if (width < 0)
  454.             return;
  455.  
  456.         int height = r.height - TF_TOP + TF_BOTTOM;
  457.         if (height < 0)
  458.             return;
  459.  
  460.         int col = TF_LEFT;
  461.         int row = 0;
  462.  
  463.         if (iTabsPosition == TOP)
  464.             row = TF_TOP;
  465.         else
  466.             row = TF_TOP - TF_BTN_HEIGHT;
  467.  
  468.         if (userPanel != null)
  469.         {
  470.             userPanel.reshape(col + 3, row + 3, width-6, height-5);
  471.             userPanel.invalidate();
  472.             userPanel.validate();
  473.             if (userPanel instanceof Canvas || userPanel instanceof Panel) {
  474.                 userPanel.repaint();
  475.             } else {
  476.                     /* userPanel.hide();
  477.                        userPanel.show(); */
  478.                 repaint();
  479.             }
  480.  
  481.         }
  482.     }
  483.  
  484.     /**
  485.      * Paints this component using the given graphics context.
  486.      * This is a standard Java AWT method which typically gets called
  487.      * by the AWT to handle painting this component. It paints this component
  488.      * using the given graphics context. The graphics context clipping region
  489.      * is set to the bounding rectangle of this component and its <0,0>
  490.      * coordinate is this component's top-left corner.
  491.      * 
  492.      * @param g the graphics context used for painting
  493.      * @see java.awt.Component#repaint
  494.      * @see java.awt.Component#update
  495.      */
  496.     public synchronized void paint(Graphics g)
  497.     {
  498.         Rectangle r = bounds();
  499.  
  500.         // --------------------------------------------------------------------------------
  501.         // paint the box
  502.         // --------------------------------------------------------------------------------
  503.  
  504.         int width = r.width - TF_LEFT + TF_RIGHT;
  505.         if (width < 0)
  506.             return;
  507.  
  508.         int height = r.height - TF_TOP + TF_BOTTOM;
  509.         if (height < 0)
  510.             return;
  511.  
  512.         if (r.width > lastWidth)
  513.             firstVisibleTab = 0;
  514.         lastWidth = r.width;
  515.  
  516.         int col = TF_LEFT;
  517.         int row;
  518.  
  519.         Color c = g.getColor();
  520.         g.setColor(getBackground());
  521.         g.fillRect(0, 0, r.width, r.height);
  522.  
  523.         if (iTabsPosition == TOP)
  524.             row = TF_TOP;
  525.         else
  526.             row = TF_TOP - TF_BTN_HEIGHT;
  527.  
  528.         // --------------------------------------------------------------------------------
  529.         // draw border
  530.         // --------------------------------------------------------------------------------
  531.         g.setColor(Color.white);
  532.         g.drawLine(col, row, (col + width - 1), row);
  533.         g.drawLine(col, row, col, (row + height - 1));
  534.  
  535.         g.setColor(Color.gray);
  536.         g.drawLine((col + 2), (row + height - 2), (col + width - 2), (row + height - 2));
  537.         g.drawLine((col + width - 2), (row + 2), (col + width - 2), (row + height - 2));
  538.  
  539.         g.setColor(Color.black);
  540.         g.drawLine((col + 1), (row + height - 1), (col + width - 1), (row + height - 1));
  541.         g.drawLine((col + width - 1), (row + 1), (col + width - 1), (row + height - 1));
  542.  
  543.         // --------------------------------------------------------------------------------
  544.         // paint the tabs, and record areas
  545.         // --------------------------------------------------------------------------------
  546.         int x1;
  547.         int x2 = TF_LEFT + 8;
  548.         int y1;
  549.         int y2;
  550.         int x3 = 0;
  551.         int x4 = TF_LEFT;
  552.  
  553.         int sze = vLabels.size();
  554.         String sLabel;
  555.         vPolys.removeAllElements();
  556.  
  557.         Font f = g.getFont();
  558.         FontMetrics fm = getFontMetrics(fReg);
  559.         FontMetrics fms = getFontMetrics(fSel);
  560.         int labelWidth = 0;
  561.         Polygon p;
  562.  
  563.         int w;
  564.         // make sure there is a polygon for each tab
  565.         for (w = 0; w < firstVisibleTab; w++)
  566.         {
  567.             vPolys.addElement(nullPoly);
  568.         }
  569.         if (w > 0)
  570.             x4 += 2;
  571.         for (; w < sze; w++)
  572.         {
  573.             p = new Polygon();
  574.             try
  575.             {
  576.                 sLabel = (String) vLabels.elementAt(w);
  577.                 if (w == curIndex)
  578.                     labelWidth = fms.stringWidth(sLabel);
  579.                 else
  580.                     labelWidth = fm.stringWidth(sLabel);
  581.  
  582.                 if (iTabsPosition == TOP)
  583.                 {
  584.                     y1 = TF_TOP - TF_BTN_HEIGHT;
  585.                     y2 = TF_TOP - 1;
  586.                 }
  587.                 else
  588.                 {
  589.                     y1 = r.height + TF_BOTTOM + 1;
  590.                     y2 = r.height + TF_BOTTOM - TF_BTN_HEIGHT;
  591.                 }
  592.  
  593.                 if (iTabsStyle == ROUNDED)
  594.                 {
  595.                     x1 = x4 + 2;
  596.                     x2 = x1 + labelWidth + 13;
  597.                 }
  598.                 else
  599.                 {
  600.                     x1 = x2 - 7;
  601.                     x2 = x1 + labelWidth + 28;
  602.                 }
  603.  
  604.                 // check to see if this tab would draw too far
  605.                 if ( (x2 + 36 - TF_RIGHT) > r.width )
  606.                     break;
  607.  
  608.                 // draw the outside edge of the tab
  609.                 if (iTabsPosition == TOP)
  610.                 {
  611.                     // if current tab, it extends further
  612.                     if (w == curIndex)
  613.                     {
  614.                         y1 -= 3;
  615.                         x1 -= 2;
  616.                     }
  617.                     g.setColor(Color.white);
  618.                     if (curIndex == (w + 1))
  619.                         g.drawLine(x1+2, y1, x2-2, y1);
  620.                     else
  621.                         g.drawLine(x1+2, y1, x2, y1);
  622.  
  623.                     // draw the border between tabs if not covered by the current one
  624.                     if (curIndex != (w - 1))
  625.                     {
  626.                         g.drawLine(x1, y1+2, x1, y2);
  627.                         x3 = x1;
  628.                     }
  629.                     else
  630.                         x3 = x1 + 1;
  631.  
  632.                     g.drawLine(x1+1, y1+1, x1+1, y1+1);
  633.  
  634.                     if (curIndex != (w + 1))
  635.                     {
  636.                         g.setColor(Color.gray);
  637.                         g.drawLine(x2, y1, x2, y2);
  638.                         g.setColor(Color.black);
  639.                         g.drawLine(x2+1, y1+2, x2+1, y2);
  640.                         x4 = x2;
  641.                     }
  642.                     else
  643.                         x4 = x2 - 1;
  644.                 }
  645.                 else
  646.                 {
  647.                     if (iTabsStyle == SQUARE)
  648.                     {
  649.                         g.setColor(Color.gray);
  650.                         g.drawLine(x1+9, y1, x2-9, y1);
  651.  
  652.                         g.setColor(Color.black);
  653.                         // left \ slanted line
  654.                         if (w == 0 || w == curIndex)
  655.                         {
  656.                             g.drawLine(x1, y2, x1+9, y1);
  657.                             p.addPoint(x1, y2);
  658.                         }
  659.                         else
  660.                         {
  661.                             g.drawLine(x1+4, y1-9, x1+9, y1);
  662.                             p.addPoint(x1+9, y2);
  663.                             p.addPoint(x1+4, y1-9);
  664.                         }
  665.                         p.addPoint(x1+9, y1);
  666.                         p.addPoint(x2-9, y1);
  667.  
  668.                         if ((w+1) == curIndex)
  669.                         {
  670.                             g.drawLine(x2-5, y1-9, x2-9, y1);
  671.                             p.addPoint(x2-5, y1);
  672.                             p.addPoint(x2-9, y2);
  673.                         }
  674.                         else
  675.                         {
  676.                             g.drawLine(x2, y2, x2-9, y1);
  677.                             p.addPoint(x2, y2);
  678.                         }
  679.  
  680.                         if (w == 1 || w == curIndex)
  681.                             p.addPoint(x1, y2);
  682.                         else
  683.                             p.addPoint(x1+9, y2);
  684.                     }
  685.                     else
  686.                     {
  687.                         // if current tab, it extends further
  688.                         if (w == curIndex)
  689.                         {
  690.                             y1 += 3;
  691.                             x1 -= 2;
  692.                         }
  693.                         g.setColor(Color.white);
  694.                         if (curIndex == (w + 1))
  695.                             g.drawLine(x1+2, y1, x2-2, y1);
  696.                         else
  697.                             g.drawLine(x1+2, y1, x2, y1);
  698.  
  699.                         // draw the border between tabs if not covered by the current one
  700.                         if (curIndex != (w - 1))
  701.                         {
  702.                             g.drawLine(x1, y1-2, x1, y2);
  703.                             x3 = x1;
  704.                         }
  705.                         else
  706.                             x3 = x1 + 1;
  707.  
  708.                         g.drawLine(x1+1, y1-1, x1+1, y1-1);
  709.  
  710.                         if (curIndex != (w + 1))
  711.                         {
  712.                             g.setColor(Color.gray);
  713.                             g.drawLine(x2, y1, x2, y2);
  714.                             g.setColor(Color.black);
  715.                             g.drawLine(x2+1, y1-2, x2+1, y2);
  716.                             x4 = x2;
  717.                         }
  718.                         else
  719.                             x4 = x2 - 1;
  720.                     }
  721.                 }
  722.  
  723.                 // draw the inside edge of the tab
  724.                 if (w == curIndex)
  725.                 {
  726.                     if (iTabsPosition == TOP)
  727.                         y2++;
  728.                     else
  729.                         y2--;
  730.                     g.setColor(getBackground());
  731.                     g.drawLine(x1+1, y2, x2, y2);
  732.                     if (iTabsPosition == BOTTOM)
  733.                         g.drawLine(x1+1, y2-1, x2, y2-1);
  734.  
  735.                     g.setFont(fSel);
  736.                 }
  737.                 else
  738.                     g.setFont(fReg);
  739.  
  740.                 // if (iTabsPosition == TOP)
  741.                 if (iTabsStyle == ROUNDED)
  742.                 {
  743.                     p.addPoint(x3, y2);
  744.                     p.addPoint(x4, y2);
  745.                     p.addPoint(x4, y1);
  746.                     p.addPoint(x3, y1);
  747.                     p.addPoint(x3, y2);
  748.                 }
  749.                 vPolys.addElement(p);
  750.  
  751.                 Boolean bool = (Boolean) vEnabled.elementAt(w);
  752.                 if (bool.booleanValue())
  753.                     g.setColor(Color.black);
  754.                 else
  755.                     g.setColor(Color.gray);
  756.  
  757.                 if (iTabsPosition == TOP)
  758.                     g.drawString(sLabel, x1+8, y1+15+osAdjustment);
  759.                 else
  760.                 {
  761.                     if (iTabsStyle == ROUNDED)
  762.                         g.drawString(sLabel, x1+8, y1-6+osAdjustment);
  763.                     else
  764.                         g.drawString(sLabel, x1+14, y1-4+osAdjustment);
  765.                 }
  766.             }
  767.             catch (ArrayIndexOutOfBoundsException e) {}
  768.         }
  769.  
  770.         // do I need to show arrows because there are too many tabs???
  771.         if ( (firstVisibleTab > 0) || (w < sze) )
  772.         {
  773.             dbLeft.show();
  774.             dbRight.show();
  775.             if (firstVisibleTab > 0)
  776.                 dbLeft.enable();
  777.             else
  778.                 dbLeft.disable();
  779.  
  780.             if (w < sze)
  781.                 dbRight.enable();
  782.             else
  783.                 dbRight.disable();
  784.  
  785.             if (iTabsPosition == TOP)
  786.             {
  787.                 dbLeft.reshape(r.width-33+TF_RIGHT, TF_TOP - 16, 16, 15);
  788.                 dbRight.reshape(r.width-16+TF_RIGHT, TF_TOP - 16, 16, 15);
  789.             }
  790.             else
  791.             {
  792.                 dbLeft.reshape(r.width-33+TF_RIGHT, r.height + TF_BOTTOM - TF_BTN_HEIGHT, 16, 15);
  793.                 dbRight.reshape(r.width-16+TF_RIGHT, r.height + TF_BOTTOM - TF_BTN_HEIGHT, 16, 15);
  794.             }
  795.         }
  796.         else
  797.         {
  798.             dbLeft.hide();
  799.             dbRight.hide();
  800.         }
  801.  
  802.         // make sure there is a polygon for each tab
  803.         for (; w < sze; w++)
  804.         {
  805.             vPolys.addElement(nullPoly);
  806.         }
  807.  
  808.         g.setFont(f);
  809.         g.setColor(c);
  810.     }
  811.  
  812.     /**
  813.      * Processes events for this component.
  814.      * This is a standard Java AWT method which gets called by the AWT
  815.      * to handle this component's events. The default handler for 
  816.      * components dispatches to one of the following methods as needed:
  817.      * action(), gotFocus(), lostFocus(), keyDown(), keyUp(), mouseEnter(),
  818.      * mouseExit(), mouseMove(), mouseDrag(), mouseDown(), or mouseUp().
  819.      *
  820.      * @param evt the event to handle
  821.      * @return true if the event was handled and no further action is needed,
  822.      * false to pass the event to this component's parent
  823.      * @see java.awt.Component#action
  824.      * @see java.awt.Component#gotFocus
  825.      * @see java.awt.Component#lostFocus
  826.      * @see java.awt.Component#keyDown
  827.      * @see java.awt.Component#keyUp
  828.      * @see java.awt.Component#mouseEnter
  829.      * @see java.awt.Component#mouseExit
  830.      * @see java.awt.Component#mouseMove
  831.      * @see java.awt.Component#mouseDrag
  832.      * @see java.awt.Component#mouseDown
  833.      * @see java.awt.Component#mouseUp
  834.      */
  835.     public boolean handleEvent(Event evt)
  836.     {
  837.         switch (evt.id)
  838.         {
  839.             case Event.MOUSE_DOWN:
  840.                 int sizeR = vPolys.size();
  841.                 Polygon p;
  842.                 for (int x = 0; x < sizeR; x++)
  843.                 {
  844.                     try
  845.                     {
  846.                         p = (Polygon) vPolys.elementAt(x);
  847.                         if ( (p != nullPoly) && p.inside(evt.x, evt.y) )
  848.                         {
  849.                             showTab(x);
  850.                             return true;
  851.                         }
  852.                     }
  853.                     catch (ArrayIndexOutOfBoundsException e) {}
  854.                 }
  855.                 break;
  856.  
  857.             case Event.ACTION_EVENT:
  858.                 if (evt.target == dbLeft)
  859.                 {
  860.                     if (--firstVisibleTab < 0)
  861.                         firstVisibleTab = 0;
  862.                     else
  863.                         repaint();
  864.                     return true;
  865.                 }
  866.                 else if (evt.target == dbRight)
  867.                 {
  868.                     int sze = vLabels.size();
  869.                     if (++firstVisibleTab == sze)
  870.                         firstVisibleTab--;
  871.                     else
  872.                         repaint();
  873.                     return true;
  874.                 }
  875.                 break;
  876.         }
  877.         return super.handleEvent(evt);
  878.     }
  879.  
  880.     // ===========================================================
  881.     // Component functions overridden so user cannot change the
  882.     // way this container should work
  883.     // ===========================================================
  884.     /**
  885.      * Takes no action.
  886.      * This is a standard Java AWT method which gets called to add a
  887.      * component to a container. 
  888.      * It is overridden here to do nothing, so the user cannot change the way
  889.      * this container should work. Use setPanel, showPanel, addTab, and setTab
  890.      * instead.
  891.      *
  892.      * @param comp the component to add (IGNORED)
  893.      * @return the added component
  894.      * @see #setPanel
  895.      * @see #showPanel
  896.      * @see #addTab
  897.      * @see #setTab
  898.      * @see #remove
  899.      */
  900.     public Component add(Component comp) { return comp; }
  901.     /**
  902.      * Takes no action.
  903.      * This is a standard Java AWT method which gets called to add a
  904.      * component to a container. 
  905.      * It is overridden here to do nothing, so the user cannot change the way
  906.      * this container should work. Use setPanel, showPanel, addTab, and setTab
  907.      * instead.
  908.      *
  909.      * @param comp the component to add (IGNORED)
  910.      * @param pos the zero-relative index at which to add the component or -1 
  911.      * for end (IGNORED)
  912.      * @return the added component
  913.      * @see #setPanel
  914.      * @see #showPanel
  915.      * @see #addTab
  916.      * @see #setTab
  917.      * @see #remove
  918.      */
  919.     public synchronized Component add(Component comp, int pos) { return comp; }
  920.     /**
  921.      * Takes no action.
  922.      * This is a standard Java AWT method which gets called to add a
  923.      * component to a container. 
  924.      * It is overridden here to do nothing, so the user cannot change the way
  925.      * this container should work. Use setPanel, showPanel, addTab, and setTab
  926.      * instead.
  927.      *
  928.      * @param name the positioning directive for the layout manager (IGNORED)
  929.      * @param comp the component to add (IGNORED)
  930.      * @return the added component
  931.      * @see #setPanel
  932.      * @see #showPanel
  933.      * @see #addTab
  934.      * @see #setTab
  935.      * @see #remove
  936.      */
  937.     public synchronized Component add(String name, Component comp) { return comp; }
  938.  
  939.     /**
  940.      * Removes the specified component from this container.
  941.      * This is a standard Java AWT method which gets called to remove a
  942.      * component from a container. When this happens the component's 
  943.      * removeNotify() will also get called to indicate component removal.
  944.      * 
  945.      * @param comp the component to remove
  946.      * @see #removeAll
  947.      * @see #add
  948.      */
  949.     public synchronized void remove(Component comp)
  950.     {
  951.         if (comp == dbLeft || comp == dbRight)
  952.             return;
  953.            super.remove(comp);
  954.         if (comp == (Component) userPanel)
  955.                userPanel = null;
  956.     }
  957.  
  958.     /**
  959.      * Removes all the components from this container.
  960.      * This is a standard Java AWT method which gets called to remove all
  961.      * the components from a container. When this happens each component's 
  962.      * removeNotify() will also get called to indicate component removal.
  963.      * 
  964.      * @see #remove
  965.      * @see #add
  966.      */
  967.     public synchronized void removeAll()
  968.     {
  969.         super.removeAll();
  970.         super.add(dbLeft, -1);
  971.         super.add(dbRight, -1);
  972.         userPanel = null;
  973.     }
  974.  
  975.     /**
  976.      * Takes no action. 
  977.      * This is a standard Java AWT method which gets called to specify
  978.      * which layout manager should be used to layout the components in
  979.      * standard containers.
  980.      *
  981.      * Since layout managers CANNOT BE USED with this container the standard
  982.      * setLayout has been OVERRIDDEN for this container and does nothing.
  983.      *
  984.      * @param l the layout manager to use to layout this container's components
  985.      * (IGNORED)
  986.      * @see java.awt.Container#getLayout
  987.      **/
  988.     public void setLayout(LayoutManager mgr) {}
  989.  
  990.     /**
  991.      * Returns the amount of space used by the current border.
  992.      * This is a standard Java AWT method which gets called to determine
  993.      * the size of the current border. The returned value is the width
  994.      * of each border side in pixels.
  995.      *
  996.      * @return the current border insets
  997.      */
  998.     public Insets insets()
  999.     {
  1000.         btpInsets = super.insets();
  1001.         btpInsets.left += (TF_LEFT + 3);
  1002.         btpInsets.right += (6 - TF_RIGHT);
  1003.  
  1004.         if (iTabsPosition == TOP)
  1005.         {
  1006.             btpInsets.top += (TF_TOP + 3);
  1007.             btpInsets.bottom += (5 - TF_BOTTOM);
  1008.         }
  1009.         else
  1010.         {
  1011.             btpInsets.top += TF_TOP - TF_BTN_HEIGHT + 3;
  1012.             btpInsets.bottom += (TF_BTN_HEIGHT + 5 - TF_BOTTOM);
  1013.         }
  1014.  
  1015.         return btpInsets;
  1016.     }
  1017.  
  1018.     /**
  1019.      * Returns the recommended dimensions to properly display this component.
  1020.      * This is a standard Java AWT method which gets called to determine
  1021.      * the recommended size of this component. 
  1022.      *
  1023.      * @see #minimumSize
  1024.      */
  1025.     public Dimension preferredSize()
  1026.     {
  1027.         Dimension s = size();
  1028.         Dimension m = minimumSize();
  1029.         return new Dimension(Math.max(s.width, m.width), Math.max(s.height, m.height));
  1030.     }
  1031.  
  1032.     /**
  1033.      * Returns the minimum dimensions to properly display this component.
  1034.      * This is a standard Java AWT method which gets called to determine
  1035.      * the minimum size of this component. 
  1036.      *
  1037.      * @see #preferredSize
  1038.      */
  1039.     public Dimension minimumSize()
  1040.     {
  1041.         if (userPanel != null)
  1042.         {
  1043.             Dimension s = userPanel.minimumSize();
  1044.             return new Dimension(    (s.width + btpInsets.left + btpInsets.right),
  1045.                                     (s.height + btpInsets.top + btpInsets.bottom) );
  1046.         }
  1047.         return new Dimension(100, 100);
  1048.     }
  1049.  
  1050.     // ===========================================================
  1051.     // Done Component functions overridden
  1052.     // ===========================================================
  1053. }
  1054.